/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  LevelDBCache.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2016/09/18
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
  ***************************************************************************************************/
#ifdef USE_LEVELDB
#include "LevelDBCache.h"



#include "../../leveldb\src\include\leveldb\db.h"
#include <iostream>
#include "SSBase/SSBase.h"
#include "KeyRecordIdHashMap.h"
using namespace ss::base;
using namespace std;
namespace ss{
	namespace ht{
		LevelDBCache::LevelDBCache(int recordSize, kDataType type, int bytes) :
			m_record_length(recordSize),
			m_record_count(0),
			m_max_recordid(-1),
			m_level_db(0),
			m_data_type(type),
			m_key_bytes(bytes)
		{
			BaseString fname = os::fmtstr("./cache/%d-%s.ldb",
				GetCurrentProcessId(), W2G(StringUtil::GenerateGuidString().c_str()).c_str());
			m_name = fname;

			leveldb::Options options;
			options.create_if_missing = true;
			leveldb::Status status = leveldb::DB::Open(options, m_name, &m_level_db);
			assert(status.ok());

			m_key_recordmap = new KeyRecordIdHashMap(type, bytes);
		}

		LevelDBCache::~LevelDBCache()
		{
			if (m_key_recordmap)	delete m_key_recordmap;
			if (m_level_db)			delete m_level_db;
		}
		RecordId LevelDBCache::GetRecordId(const char* key)
		{
			return m_key_recordmap->find(key);
		}

		bool LevelDBCache::Read(RecordId rid, char* record, int size)
		{
			BASSERT(size == m_record_length && record);
			BASSERT(m_level_db);
			if (rid > m_max_recordid)
				return false;
			if (!m_delete_map.empty() && m_delete_map.find(rid) != m_delete_map.end())
				return  false;
			
			char key[32] = { 0 };
			_itoa_s(rid, key,32, 10);

			std::string result;
			leveldb::Status s = m_level_db->Get(leveldb::ReadOptions(), key, &result);
			if (s.ok())
			{
				memcpy(record, result.c_str(), size);
				return true;
			}
			return false;
		}
		RecordId LevelDBCache::Write(RecordId rid, const void* record, int size, const char* key)
		{
			// rid = -1 表示直接插入到末尾，不修改
			BASSERT(record && size == m_record_length);
			BASSERT((rid >= 0 && rid <= m_max_recordid) || rid == -1);
			BASSERT(m_level_db);
			bool insert = false;
			if (rid == -1)
			{
				insert = true;
				m_max_recordid++;
				m_record_count++;
				rid = m_max_recordid;
				m_key_recordmap->insert((char*)key, rid);
			}

			char idbuf[32] = { 0 };
			_itoa_s(rid, idbuf,32, 10);
			leveldb::Slice idkey(idbuf, strlen(idbuf));
			leveldb::Slice idvalue((const char*)record, size);
			leveldb::Status s = m_level_db->Put(leveldb::WriteOptions(), idkey,idvalue);
			return rid;
		}

		void LevelDBCache::SetCapcity(int capcity)
		{
			m_key_recordmap->Expand(capcity);
		}

		int LevelDBCache::GetMemoryBytes()const
		{
			int bytes = sizeof(*this);
			if (m_key_recordmap)
				bytes += m_key_recordmap->GetMemoryBytes();
			if (m_level_db)
			{
				leveldb::Slice name("leveldb.approximate-memory-usage");
				std::string value;
				m_level_db->GetProperty(name, &value);
				bytes += (int)_atoi64(value.c_str());
			}
			return bytes;
		}
	}//namespace ht
}//namespace ss

#endif // USE_LEVELDB
